#ifndef _OBJECT_H
#define _OBJECT_H

typedef set<Object*> ObjectInRangeSet;

enum TypeId
{
	TYPEID_OBJECT			= 0x00,
	TYPEID_ITEM				= 0x01,
	TYPEID_CONTAINER		= 0x02,
	TYPEID_UNIT				= 0x03,
	TYPEID_PLAYER			= 0x04,
	TYPEID_GAMEOBJECT		= 0x05,
	TYPEID_DYNAMICOBJECT	= 0x06,
	TYPEID_CORPSE			= 0x07,
	TYPEID_AIGROUP			= 0x08,
	TYPEID_AREATRIGGER		= 0x09,
};

class DLL_EXPORT Object : public EventHolder
{
	friend class MapHandler;
	friend class Player;
	friend class Item;
	friend class MapCell;
protected:
	UpdateMask m_updatemask;
	WoWGuid m_guid;
	ui32 m_fieldcount;
	ui32 m_speedchanged;
	float m_runspeed;
	float m_backrunspeed;
	float m_walkspeed;
	float m_flyspeed;
	float m_backflyspeed;
	float m_swimspeed;
	float m_backswimspeed;
	float m_turnspeed;
	bool m_update;
	bool m_moved;
	Landmark m_position;
	ui32 m_zone;
	float m_orientation;
	MapHandler* m_maphandler;
	TypeId m_typeid;
	union
	{
		ui32* m_ui32values;
		float* m_floatvalues;
	};
	void BuildCreation(Player* target, RealmPacket* buffer);
	void BuildFieldUpdates(RealmPacket* buffer);
	void BuildMoveUpdates(RealmPacket* buffer, ui32 flags);
	void BuildValuesUpdate(RealmPacket* buffer);
	void UpdateInRangeSet(RealmPacket* data, bool Creation);
	ObjectInRangeSet m_inrangeset;
	set<Player*> m_inrangeplayers;
	virtual void AddInRangeObject(Object* obj);
	virtual void PushOutOfRange(Object* obj) 
	{ 
		m_inrangeset.erase(obj);
		if(obj->GetTypeId() == TYPEID_PLAYER)
			m_inrangeplayers.erase((Player*)obj);
	}
	virtual void ClearAllInrange() { m_inrangeset.clear(); }
	virtual void RemoveFromWorld() { }
	MapCell* m_mapcell;
public:
	void PackGuid(RealmPacket* pOut);
	void SetUI32Value(ui32 index, ui32 value);
	void SetFloatValue(ui32 index, float value);
	void SetFlag(ui32 index, ui32 value);
	void RemoveFlag(ui32 index, ui32 value);
	void SetByte(ui32 index, ui32 position, ui8 value);
	ui8 GetByte(ui32 index, ui8 position);
	void SendToSet(RealmPacket& data);
	Object();
	virtual ~Object();
	const WoWGuid& GetNewGUID() { return m_guid; }
	const ui32 GetUI32Value(ui32 index) const
	{
		if(index >= m_fieldcount)
			return 0;
		return m_ui32values[index];
	}

	const ui64 GetGUID() const
	{
		return *(ui64*)m_ui32values;
	}

	void SetUI64Value(ui32 index, ui64 value)
	{
		if(index + 1 >= m_fieldcount)
			return;
		*(ui64*)(&m_ui32values[index]) = value;
		m_updatemask.SetBit(index);
		m_updatemask.SetBit(index + 1);
		m_update = true;
		if(m_maphandler)
			m_maphandler->AddUpdateObject(this);
	}

	const ui64 GetUI64Value(ui32 index) const
	{
		if(index + 1 >= m_fieldcount)
			return 0;
		return *(ui64*)(&m_ui32values[index]);
	}

	MapHandler* const GetMapHandler() const { return m_maphandler; }

	const Landmark GetPosition() { return m_position; }
	void SetPosition(float x, float y, float z, float o = 1.0f)
	{
		m_position._x = x;
		m_position._y = y;
		m_position._z = z;
		m_orientation = o;
	}
	void SetPosition(float x, float y, float z, ui32 mapid, float o = 1.0f)
	{
		m_position._x = x;
		m_position._y = y;
		m_position._z = z;
		m_position._mapid = mapid;
		m_orientation = o;
	}
	void SetPosition(Landmark& position)
	{
		m_position = position;
	}

	TypeId GetTypeId() { return m_typeid; }
	ui32 GetZoneId() { return m_zone; }
	ui32 GetEntry() { return GetUI32Value(OBJECT_FIELD_ENTRY); }
	float GetOrientation() { return m_orientation; }
	set<Object*>::iterator GetInRangeSetBegin() { return m_inrangeset.begin(); }
	set<Object*>::iterator GetInRangeSetEnd() { return m_inrangeset.end(); }

	virtual void OnPushToWorld() { }
};

#endif